//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include <bulverde.h>
#include "display_def.h"
#include <udelay.h>
#define SPI_SCLK    36
#define SPI_TXD     13
#define SPI_FRM     14
#define SPI_RXD     11

#define LCD_nRESET  24

// GPIO
#define GPIO_PIN_IN 0
#define GPIO_PIN_OUT    1

#define GPIO_AS_GPIO    0
#define GPIO_AS_AF1 1
#define GPIO_AS_AF2 2
#define GPIO_AS_AF3 3

void Gpio_SetDir(int gpio_num, int direction);
void Gpio_SetAFR(int gpio_num, int function);
void Gpio_SetOutLow(int gpio_num);
void Gpio_SetOutHigh(int gpio_num);

static void SPI2Init(void)
{
#define CKEN3_SSP2      (1 << 3)    /* SSP2 Unit Clock Enable */
    CKEN |= CKEN3_SSP2;

    Gpio_SetDir(SPI_SCLK, GPIO_PIN_OUT);
    Gpio_SetAFR(SPI_SCLK, GPIO_AS_AF2);
    //set spi_txd
    Gpio_SetDir(SPI_TXD, GPIO_PIN_OUT);
    Gpio_SetAFR(SPI_TXD, GPIO_AS_AF1);
    //set spi_frm  SPI_CS -- must be GPIO only because of the polarity of CS -- must be high for PMIC active
    Gpio_SetDir(SPI_FRM, GPIO_PIN_OUT);
    Gpio_SetAFR(SPI_FRM, GPIO_AS_GPIO);

    SSCR0_2 = (unsigned long)0x00C00308;//Truly spi 9bits

    SSCR1_2 = (unsigned long)0x500007C0;

    SSCR0_2 |= SSCR0_SSE;
}

void LcdHWSetup(void)
{
    int gpio_x;

    for (gpio_x = 58; gpio_x <= 76 ; gpio_x++) {
        Gpio_SetDir( gpio_x, GPIO_PIN_OUT );
        Gpio_SetOutLow(gpio_x);
        Gpio_SetAFR( gpio_x, GPIO_AS_AF2 );
    }

    Gpio_SetDir( 77, GPIO_PIN_OUT );
    Gpio_SetAFR( 77, GPIO_AS_AF2 );

    Gpio_SetDir( 86, GPIO_PIN_OUT );
    Gpio_SetOutLow(86);
    Gpio_SetAFR( 86, GPIO_AS_AF2 );

    Gpio_SetDir( 87, GPIO_PIN_OUT );
    Gpio_SetOutLow(87);
    Gpio_SetAFR( 87, GPIO_AS_AF2 );
}

static void LcdReset(void)
{
    Gpio_SetDir(LCD_nRESET, GPIO_PIN_OUT);
    Gpio_SetAFR(LCD_nRESET, GPIO_AS_GPIO);

    Gpio_SetOutHigh(LCD_nRESET);

    ostdelay(20 *1000);

    Gpio_SetOutLow(LCD_nRESET);

    ostdelay(20 *1000);

    Gpio_SetOutHigh(LCD_nRESET);
}

void SPIWrite(unsigned short data)
{

    SSCR0_2 |= SSCR0_SSE;

    Gpio_SetOutLow(SPI_FRM);

    SSDR_2 = data;

    SSCR0_2 |= SSCR0_SSE;

    while( SSSR_2 & SSSR_BSY ) { }
    ;

    Gpio_SetOutHigh(SPI_FRM);
}

void LcdWritePara(unsigned short data)
{
    data |= ( 0x1<<8 );
    SPIWrite(data);
}

void LcdWriteCmd(unsigned short data)
{
    data &= 0x0FF;
    SPIWrite(data);
}

void LcdTrulyInit(void)
{
    LcdWriteCmd(0x92); //OSC ON
    ostdelay(8);

    LcdWriteCmd(0x99); //soft start
    ostdelay(8);//

    LcdWriteCmd(0x31);
    LcdWritePara(0x87);//DING CHANGE Origin 0x00 //0B
    LcdWritePara(0x00); //ding change origin 0x00 //01

    /**************/

    LcdWriteCmd(0x96); //VDD ON
    ostdelay(6);//

    LcdWriteCmd(0x6F);
    LcdWritePara(0x00);

    /****************/

    LcdWriteCmd(0xBC);
    LcdWritePara(0x00);

    /**************/
    LcdWriteCmd(0xCA); //set display
    LcdWritePara(0x32);//DING ORIGIN 0x25
    LcdWritePara(0x00); //
    LcdWritePara(0x01);
    LcdWritePara(0x3F);
    LcdWritePara(0x02);//ding back-porch
    LcdWritePara(0x00);
    LcdWritePara(0x01);//ding ori 01

    ostdelay(4);//

    /************/
    LcdWriteCmd(0xA1);  //set display timing
    LcdWritePara(0x00);//00  //EPSON CHANGE 01
    LcdWritePara(0x9F);//9f  //EPSON CHANGE 29
    LcdWritePara(0x07);//07  //EPSON CHANGE 03
    LcdWritePara(0x9D);//9d  //EPSON CHANGE 26
    LcdWritePara(0x73);
    LcdWritePara(0xA1);
    LcdWritePara(0x00);
    /**************/

    LcdWriteCmd(0x20);
    LcdWritePara(0x10);//vddhs
    LcdWritePara(0x18);
    LcdWritePara(0x1A);
    LcdWritePara(0x11);
    LcdWritePara(0x11);
    LcdWritePara(0x10);
    LcdWritePara(0x07);//vddrh
    ostdelay(10);//
    /**************/

    /*************/
    LcdWriteCmd(0x21);
    LcdWritePara(0x01);
    LcdWritePara(0x0F);
    LcdWritePara(0x0F);
    LcdWritePara(0xFE);
    LcdWritePara(0x33);
    LcdWritePara(0x31);
    LcdWritePara(0xFF);
    LcdWritePara(0x00);
    LcdWritePara(0x00);
    LcdWritePara(0x22);
    LcdWritePara(0x33);
    LcdWritePara(0x11);
    LcdWritePara(0x44);
    LcdWritePara(0x00);
    ostdelay(10);//
    /*****************/

    LcdWriteCmd(0x22);
    LcdWritePara(0x14);
    LcdWritePara(0xC1);
    LcdWritePara(0x26);
    LcdWritePara(0x2A);
    LcdWritePara(0x23);
    LcdWritePara(0x04);
    /**************/

    LcdWriteCmd(0x25);
    LcdWritePara(0x14);
    LcdWritePara(0xC1);
    LcdWritePara(0x26);
    LcdWritePara(0x2A);
    LcdWritePara(0x23);
    LcdWritePara(0x04);

    /************/
    LcdWriteCmd(0x23);
    LcdWritePara(0x33);
    LcdWritePara(0xFF);
    LcdWritePara(0x00);
    LcdWritePara(0x00);
    LcdWritePara(0x44);
    LcdWritePara(0x00);
    /*************/

    LcdWriteCmd(0x94);
    ostdelay(10);//
    /**************/

    LcdWriteCmd(0xAB);
    LcdWritePara(0x00);
    LcdWritePara(0x00);

    /**************/
    /*****************/
    LcdWriteCmd(0x15);
    LcdWritePara(0x00);
    LcdWritePara(0x00);
    LcdWritePara(0x00);
    /****************/

    LcdWriteCmd(0x75);
    LcdWritePara(0xEF);
    LcdWritePara(0x01);
    LcdWritePara(0x3F);
    /****************/

    LcdWriteCmd(0xA9); //cancels partial display

    LcdWriteCmd(0x8B);

    LcdWritePara(0x00);

    /************/

    LcdWriteCmd(0xAF);
    ostdelay(15);//

    LcdWriteCmd(0x5C);
}

///////////////////////////////////////////////////////////////////////////////

void Lcm_SetupGPIOs(DisplayContext *pCxt)
{
    // 16bpp support
    // bits 58-77
    GPDR1 |= (0x3f << 26);
    GPDR2 |= 0x00003fff;

    GAFR1_U = (GAFR1_U & ~(0xfff << 20)) | (0xaaa << 20);
    GAFR2_L = (GAFR2_L & 0xf0000000) | 0x0aaaaaaa;
}

void Lcm_DisplayOn(DisplayContext *pCxt)
{
    SPI2Init();
    LcdHWSetup();
    LcdReset();
    ostdelay(10 * 1000);
    LcdTrulyInit();
}

void Lcm_DisplayOff(DisplayContext *pCxt)
{
}
